import java.io.*;
import java.util.Date;
import java.util.Calendar;

/**
* Does the different operations of read, write, etc
*/
public class Operations {
	
	private String result = "";//To save error messages
	private String t_m = "00:00:00";
	private String content = "";//To save new contents 
	
	public Operations() {
	
	}
	
   /**
	* Get error messages received
	*/
	public String getResult() {
		return result;
	}
	
   /**
	* Get contents that need to be returned
	*/
	public String getContent() {
		return content;
	}
	
   /**
    * Method to get the value of last modified 
	* time of file variable in String format "HH:MM:SS"
	*/
	public String getTM() {
		return t_m;
	}
	
   /**
    * Method to update the last modified time of file
	*@return true	if successful, otherwise false
	*/
	public boolean getTM(String filename) {
		try {
			File f = new File(filename);
			if(f.exists()){
				Date date = new Date(f.lastModified());
				Calendar calendar = java.util.GregorianCalendar.getInstance();
				calendar.setTime(date);
				//Save the value into HH:MM:SS format
				t_m = calendar.get(Calendar.HOUR_OF_DAY)+":"
					+calendar.get(Calendar.MINUTE)+":"
					+calendar.get(Calendar.SECOND);
				return true;
			} else {
				result = "The file " + filename.trim() + " does not exist.";
			}
		} catch(SecurityException  e) {
			result = "Access to file is denied.";
		}
		return false;
	}	
	
   /**
    * Method to read whole of file contents
	*@return true	if successful, otherwise false
	*/
	public boolean readFile(String filename) {
		try {
            RandomAccessFile raf = new RandomAccessFile(filename, "r");
            raf.seek(0); 
			// Read in the entire file
            byte[] arr = new byte[(int)raf.length()];
            raf.readFully(arr);
            content = new String(arr);
            //System.out.println("DEBUG: readFully as string: " + content);
            getTM(filename); 
			raf.close();
			return true;
		} catch(FileNotFoundException e) {
			result = "The file " + filename.trim() + " is not found.";
		} catch(IOException e) {
			result = "An IO Exception occurred.";
		}
		return false;
	}
	
   /**
	*@return true	if successful, otherwise false
	*/
	public boolean randomRead(String filename,int offset,int numOfBytes) {
		try {
			RandomAccessFile raf = new RandomAccessFile(filename,"r");
			raf.seek(offset);
			byte[] buffer = new byte[numOfBytes];
			int size = raf.read(buffer,offset,numOfBytes);
			//System.out.println("DEBUG: contents read is: "+(new String(buffer)));
			content = new String(buffer);
			getTM(filename);
			raf.close();
			return true;
		} catch(FileNotFoundException e) {
			result = "The file " + filename.trim() + " is not found.";
		} catch(IOException e) {
			result = "An IO Exception occurred.";
		} catch(IndexOutOfBoundsException e) {
			result = "Out of bounds exception";
		}
		return false;
	}
	
   /**
	*@return true	if successful, otherwise false
	*/
	public boolean randomWrite(String filename,int offset,String contents) {
		try {
			RandomAccessFile raf = new RandomAccessFile(filename,"rw");
			raf.seek(0);
			int length = (int)raf.length();		
			//Check if offset is OutOfBounds
			if(offset < 0 || offset >= length) {
				throw new IndexOutOfBoundsException();
			} else {
				readFile(filename);
				String original = content;
				//System.out.println("DEBUG: originalfile="+ original);
				String Contentsb4Off = original.substring(0,offset);
				String ContentsAfterOff = contents + original.substring(offset,length);
				//System.out.println("DEBUG: Contentb4Off="+ Contentsb4Off);
				//System.out.println("DEBUG: ContentsAfterOff="+ ContentsAfterOff);
				String newContent = Contentsb4Off + ContentsAfterOff;
				//System.out.println("DEBUG: newContent="+newContent);
				raf.write(newContent.getBytes());
				getTM(filename);
				raf.close();
				return true;
			}
		} catch(FileNotFoundException e) {
			result = "The file " + filename.trim() + " is not found.";
		} catch(IOException e) {
			result = "An IO Exception occurred.";
		} catch(IndexOutOfBoundsException e) {
			result = "Out of bounds exception";
		}
		return false;
	}
	
   /**
	* Append new contents to the end of file
	*@return true	if successful, otherwise false
	*/
	public boolean appendWrite(String filename,String contents) {
		try {
			RandomAccessFile raf = new RandomAccessFile(filename,"rw");
			int length = (int)raf.length();
			raf.seek(0);
			int offset = length-1;
			//Check if offset is OutOfBounds
			if(offset < 0 || offset >= length) {
				throw new IndexOutOfBoundsException();
			} else {
				readFile(filename);
				String original = content;
				//System.out.println("DEBUG: originalfile="+ original);
				String newContent = content + contents;
				//System.out.println("DEBUG: newContent="+newContent);
				raf.write(newContent.getBytes());
				getTM(filename);
				raf.close();
				return true;
			}
		} catch(FileNotFoundException e) {
			result = "The file " + filename.trim() + " is not found.";
		} catch(IOException e) {
			result = "An IO Exception occurred.";
		} catch(IndexOutOfBoundsException e) {
			result = "Out of bounds exception";
		}
		return false;
	}
	
   /**
	* Creates a new empty file
	*@return true	if successful, otherwise false
	*/
	public boolean createFile(String filename) {
		try {
			File f = new File(filename);
			if(!f.exists()){
				f.createNewFile();
				getTM(filename);
				return true;
			} else {
				result = "The file " + filename.trim() + " already exists.";
			}
		} catch(IOException e) {
			result = "An IO Exception occurred.";
		} catch(SecurityException  e) {
			result = "Access to file is denied.";
		}
		return false;
	}
	
   /**
	* Checks if a file exists
	*@return true	if file exists, otherwise false
	*/
	public boolean fileExists(String filename) {
		File f = new File(filename);
		if(f.exists()){
			return true;
		}
		result = "The file " + filename.trim() + " does not exist.";
		return false;
	}
	
}